#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string>

//环境变量
#define MAX_ENVC 100
int g_envc = 0;
char* g_env[MAX_ENVC];
char** my_environ;

// cwd
#define MAX_CWD_SIZE 1024
char g_cwd[MAX_CWD_SIZE];
char g_cwdenv[MAX_CWD_SIZE+4];

//prompt
#define FORMAT "[%s@%s %s]# "
#define PROMPTSIZE 1024

//command
#define MAX_CMD_SIZE 1024

//命令行参数表
#define MAX_ARGC 128
char* g_argv[MAX_ARGC];
int g_argc = 0;

void InitEnv()
{
    extern char** environ;
    for(int i = 0;environ[i];++i)
    {
        g_env[i] = (char*)malloc(strlen(environ[i])+1);
        strcpy(g_env[i],environ[i]);
        ++g_envc;
    }
    my_environ = g_env;
}

void CleanEnv()
{
    for(int i = 0;g_env[i];++i)
    {
        free(g_env[i]);
        g_env[i] = nullptr;
    }
    my_environ = nullptr;
    g_envc = 0;
}

char* GetUser()
{
    return getenv("USER"); 
}

char* GetHost()
{
    return getenv("HOSTNAME");
}

char* GetPwd()
{
    //return getenv("PWD");
    getcwd(g_cwd,sizeof(g_cwd));
    snprintf(g_cwdenv,sizeof(g_cwdenv),"PWD=%s",g_cwd);
    putenv(g_cwdenv);
    return g_cwd;
}

char* GetHome()
{
    return getenv("HOME");
}

std::string DoDir(char* cwd)
{
    std::string pwd = cwd;
    if(pwd == "/")
    {
        return pwd;
    }
    else 
    {
        size_t pos = pwd.rfind("/");
        return pwd.substr(pos+1);
    }
}

void  MakePrompt(char* prompt,int size)
{
    snprintf(prompt,size,FORMAT,GetUser(),GetHost(),DoDir(GetPwd()).c_str());
}

void  PrintCommandPrompt()
{
    char prompt[PROMPTSIZE] = {0}; 
    MakePrompt(prompt,sizeof(prompt));
    std::cout<<prompt;
    fflush(stdout);
}

bool GetCmdL(char* commandline,int size)
{
    fgets(commandline,size,stdin);
    //包含\n要处理
    commandline[strlen(commandline)-1] = 0;
    if(strlen(commandline) == 0)
    {
        return false;
    }
    return true;
}



void CmdParse(char* commandline)
{
#define SEP " "
    g_argc = 0;
    g_argv[g_argc++] = strtok(commandline,SEP);
    while(g_argv[g_argc++] = strtok(NULL,SEP));
    --g_argc;
}   

void Execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        execvp(g_argv[0],g_argv);
        exit(1);
    }
    waitpid(id,nullptr,0);
}

bool CheckBuiltin()
{
    std::string cmd = g_argv[0];
    if(cmd == "cd")
    {
        if(g_argc == 1)
        {
            chdir(GetHome());
        }
        else
        {
            std::string where = g_argv[1];
            chdir(where.c_str());
        }
        return true;
    }
    else
    {
        return false;
    }
}


int  main()
{
    InitEnv();
    while(true)
    {
       PrintCommandPrompt(); 
       char commandline[MAX_CMD_SIZE] = {0}; 
       if(!GetCmdL(commandline,sizeof(commandline)))
       {
            continue;
       }
       CmdParse(commandline);
       if(CheckBuiltin())
       {
           continue;
       }
       Execute();
    }
    CleanEnv();

    return 0;
}
